package com.wuhongyu.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import com.wuhongyu.common.MyCommon;
import com.wuhongyu.entity.Count;
import com.wuhongyu.entity.Message;
import com.wuhongyu.mapper.MessageMapper;
import com.wuhongyu.service.MessageService;
import com.wuhongyu.util.MyUtil;
import org.springframework.transaction.annotation.Transactional;

@Service("messageService")
public class MessageServiceImpl implements MessageService {
	Integer count = 0;
	// 获取日志记录器Logger，名字为本类类名
	private static volatile Logger log = LoggerFactory.getLogger(MessageServiceImpl.class);

	/**
	 * 实现多线程放入数据库的匿名内部类
	 *
	 * @author Administrator
	 */
	private class Grab implements Runnable {
		// 网址
		private String url;
		private Integer userId;

		public Grab(String url, Integer userId) {
			this.url = url;
			this.userId = userId;
		}

		@Override
		public void run() {
			log.debug(Thread.currentThread().getName() + "放入数据库开始");
			List<Message> messageList = MyUtil.getMessage(url);
			for (int i = 0; i < messageList.size(); i++) {
				Message message = messageList.get(i);
				if (!validation(message)) {
					log.debug("岗位" + message.getPost() + "不符合规则，放入数据库失败");
					continue;
				}
				message.setUserid(userId);
				messageMapper.insert(message);
				//log.debug(message.toString());
			}
			log.debug(Thread.currentThread().getName() + "放入数据库完成");
		}

	}

	@Autowired
	private ThreadPoolTaskExecutor threadPoolTaskExecutor;
	@Autowired
	private MessageMapper messageMapper;

	/**
	 * 抓取网页上的所有信息，放到数据库中
	 */
	@Override
	public void grab(String url, Integer userId) {
		long time1 = System.currentTimeMillis();
		Integer total = MyUtil.getPage(url);
		Integer page = this.getPage(total);
		if (total > MyCommon.MAX_TOTAL) {
			total = MyCommon.MAX_TOTAL;
		}
		// 截取页数的字符串
		String head = url.substring(0, url.indexOf("&p="));
		String threadUrl;
		Integer beforeCount = messageMapper.selectCount(userId);
		log.debug("抓取开始");
		for (int i = 1; i <= page; i++) {
			threadUrl = head + "&p=" + i;
			threadPoolTaskExecutor.execute(new Thread(new Grab(threadUrl, userId)));
		}

		while (threadPoolTaskExecutor.getActiveCount() > 0) {

		}
		log.debug("所有线程放入数据库完成");
		long time2 = System.currentTimeMillis();
		Integer afterCount = messageMapper.selectCount(userId);
		Integer insertCount = afterCount - beforeCount;
		log.debug(beforeCount+"");
		log.debug(afterCount+"");
		log.debug("共" + total + "条数据，成功放入" + insertCount + "条数据，耗时：" + (time2 - time1) / 1000.0 + "秒");

	}

	/**
	 * 通过总行数得到总页数
	 *
	 * @param total
	 * @return
	 */
	private Integer getPage(Integer total) {
		Integer page = 1;
		if (total > MyCommon.COUNT) {
			page = total % MyCommon.COUNT == 0 ? total / MyCommon.COUNT : total / MyCommon.COUNT + 1;
		}
		if (page > MyCommon.MAX_PAGE) {
			page = MyCommon.MAX_PAGE;
		}
		return page;
	}

	/**
	 * 统计工资
	 */
	@Override
	public List<Count> count(Integer userId) {
		log.debug("userId:" + userId + "统计开始");
		// 初始化map集合
		Map<String, Integer> map = initMap();
		// 进行统计
		count(map, userId);
		log.debug("map:" + map.toString());
		// 判断一下统计是否正确
		if (map.size() != MyCommon.kMap.size() + 1)
			throw new IllegalArgumentException("userId:" + userId + "统计出错");
		List<Count> list = new ArrayList<>();

		map.forEach((k, v) -> {
			this.count = count + v;
		});
		BigDecimal countD = new BigDecimal(count + "");
		map.forEach((k, v) -> {
			Count c = new Count();
			c.setName(k);
			c.setNumber(v.toString());
			BigDecimal p = new BigDecimal(v + "");
			BigDecimal result = p.divide(countD, 3, BigDecimal.ROUND_HALF_UP);
			BigDecimal multiply = result.multiply(new BigDecimal("100"));
			BigDecimal setScale = multiply.setScale(1, BigDecimal.ROUND_UP);
			c.setPercent(setScale);
			log.debug(setScale.toString());
			list.add(c);
		});

		log.debug("userId:" + userId + "统计结束");

		return list;
	}

	private void count(Map<String, Integer> map, Integer userId) {
		// 查询出所有的数据，准备统计
		List<Message> list = messageMapper.selectByUserId(userId);
		for (Message message : list) {
			// 得到该条数据的工资
			String salary = message.getSalary();
			// 最小工资
			Integer salary1 = null;
			// 最大工资
			Integer salary2 = null;
			// 如果工资是面议的话直接放入
			if (MyCommon.OTHERS.equals(salary)) {
				put(map, MyCommon.OTHERS);
			} else {
				// 不是面议的话就将最小工资和最大工资分开
				try {
					String[] split = salary.split("-");
					salary1 = Integer.parseInt(split[0]);
					salary2 = Integer.parseInt(split[1]);
				} catch (Exception e) {
					// 如果通过‘-’分开失败的话有两种情况
					try {
						// 情况1：工资是“1000元以下”，或者是“50000元以上”
						// 分别放入对应的map，然后结束此次循环
						String[] split = salary.split("元");
						if (split[1].equals("以下")) {
							put(map, MyCommon.H0);
						} else if (split[1].equals("以上")) {
							put(map, MyCommon.H7);
						}
						continue;
					} catch (Exception e2) {
						// 情况2：工资是一个具体的数，那么最大和最小都为这个具体的数值
						salary1 = Integer.parseInt(salary);
						salary2 = Integer.parseInt(salary);
					}
				}

				// 如果可以通过‘-’分开的话就进入统计阶段
				// 从最小的3000开始遍历，这里使用List集合是为了保证遍历的顺序
				for (Integer k : MyCommon.kList) {
					// 如果当前的k大于等于最大的工资，就放进入并且结束循环
					if (k >= salary2) {
						put(map, MyCommon.kMap.get(k));
						break;
					}
					// 如果当前k大于最小工资，放入
					if (k > salary1) {
						put(map, MyCommon.kMap.get(k));
					}
					// 由于salary2肯定会大于等于salary1，所以不可能出现其他情况
				}
			}
		}
	}

	/**
	 * 初始化map集合
	 *
	 * @return
	 */
	private Map<String, Integer> initMap() {
		Map<String, Integer> map = new TreeMap<>(new Comparator<String>() {
			// 对map集合里的工资统计正序进行排序，看起来更清晰
			@Override
			public int compare(String o1, String o2) {
				// 如果是key是‘面议’的话，就放在最后面
				if (o1.equals(MyCommon.OTHERS) && o2.equals(MyCommon.OTHERS)) {
					return 0;
				}
				if (o1.equals(MyCommon.OTHERS)) {
					return 1;
				}

				if (o2.equals(MyCommon.OTHERS)) {
					return -1;
				}
				return MyCommon.hMap.get(o1) - MyCommon.hMap.get(o2);
			}
		});
		// 初始化该map集合
		map.put(MyCommon.H0, 0);
		map.put(MyCommon.H1, 0);
		map.put(MyCommon.H2, 0);
		map.put(MyCommon.H3, 0);
		map.put(MyCommon.H4, 0);
		map.put(MyCommon.H5, 0);
		map.put(MyCommon.H6, 0);
		map.put(MyCommon.H7, 0);
		map.put(MyCommon.OTHERS, 0);
		return map;
	}

	/**
	 * 放入指定的map集合
	 *
	 * @param map
	 * @param key
	 */
	private void put(Map<String, Integer> map, String key) {
		if (map.containsKey(key)) {
			map.put(key, map.get(key) + 1);
		} else {
			map.put(key, 1);
		}
	}

	/**
	 * 校验数据的格式是否可以成功放入数据库
	 *
	 * @param message
	 * @return
	 */
	private boolean validation(Message message) {
		String rate = message.getRate();
		if (rate == null || rate.equals("") || (rate.indexOf("%")) != -1) {
			return true;
		}
		return false;
	}

}
